"""
企业级金融数据MCP服务系统 - 债券数据模型
提供完整的债券相关数据SQLAlchemy ORM模型定义
"""

from datetime import datetime, date
from decimal import Decimal
from typing import Optional, Dict, Any
from sqlalchemy import String, DateTime, Date, Boolean, Integer, Numeric, Text, Index, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import JSONB

from .base import BaseFinancialModel, DataVersionMixin, SyncStatusMixin, PartitionMixin


class BondBasicInfo(BaseFinancialModel, SyncStatusMixin):
    """
    债券基本信息模型
    存储债券的基础信息，如债券代码、名称、发行信息等
    """
    __tablename__ = "bond_basic_info"
    
    # 债券代码
    bond_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="债券代码")
    
    # 债券名称
    bond_name: Mapped[str] = mapped_column(String(100), nullable=False, comment="债券名称")
    
    # 债券简称
    bond_short_name: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="债券简称")
    
    # 交易所代码：SH(上海), SZ(深圳), IB(银行间)
    exchange: Mapped[str] = mapped_column(String(10), nullable=False, comment="交易所代码")
    
    # 债券类型：国债, 企业债, 公司债, 可转债, 金融债等
    bond_type: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="债券类型")
    
    # 发行人代码
    issuer_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="发行人代码")
    
    # 发行人名称
    issuer_name: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="发行人名称")
    
    # 发行日期
    issue_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="发行日期")
    
    # 上市日期
    list_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="上市日期")
    
    # 到期日期
    maturity_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="到期日期")
    
    # 债券期限（年）
    bond_term: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 2), nullable=True, comment="债券期限(年)")
    
    # 票面利率(%)
    coupon_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="票面利率(%)")
    
    # 发行规模（万元）
    issue_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="发行规模(万元)")
    
    # 面值（元）
    par_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 2), nullable=False, default=100, comment="面值(元)")
    
    # 付息方式：一次还本付息, 按年付息, 按半年付息等
    pay_method: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="付息方式")
    
    # 计息基准：ACT/ACT, ACT/365, 30/360等
    day_count: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="计息基准")
    
    # 信用评级
    credit_rating: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="信用评级")
    
    # 担保方式
    guarantee_type: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="担保方式")
    
    # 债券状态：发行, 上市, 摘牌, 到期
    bond_status: Mapped[str] = mapped_column(String(20), nullable=False, default="发行", comment="债券状态")
    
    # 扩展信息
    extra_info: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="扩展信息")
    
    __table_args__ = (
        UniqueConstraint('bond_code', 'exchange', name='uk_bond_basic_code_exchange'),
        Index('idx_bond_basic_exchange', 'exchange'),
        Index('idx_bond_basic_type', 'bond_type'),
        Index('idx_bond_basic_issuer', 'issuer_code'),
        Index('idx_bond_basic_issue_date', 'issue_date'),
        Index('idx_bond_basic_maturity_date', 'maturity_date'),
        Index('idx_bond_basic_status', 'bond_status'),
    )
    
    def __repr__(self) -> str:
        return f"<BondBasicInfo(bond_code={self.bond_code}, bond_name={self.bond_name}, exchange={self.exchange})>"


class BondDailyData(BaseFinancialModel, PartitionMixin):
    """
    债券日线数据模型
    存储债券的日K线数据，包括开高低收、成交量、收益率等
    """
    __tablename__ = "bond_daily_data"
    
    # 债券代码
    bond_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="债券代码")
    
    # 交易日期
    trade_date: Mapped[date] = mapped_column(Date, nullable=False, comment="交易日期")
    
    # 开盘价
    open_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="开盘价")
    
    # 最高价
    high_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="最高价")
    
    # 最低价
    low_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="最低价")
    
    # 收盘价
    close_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="收盘价")
    
    # 前收盘价
    pre_close: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="前收盘价")
    
    # 涨跌额
    change: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="涨跌额")
    
    # 涨跌幅(%)
    pct_chg: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="涨跌幅(%)")
    
    # 成交量（万元）
    volume: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="成交量(万元)")
    
    # 成交笔数
    trade_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="成交笔数")
    
    # 到期收益率(%)
    ytm: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="到期收益率(%)")
    
    # 修正久期
    modified_duration: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="修正久期")
    
    # 凸性
    convexity: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="凸性")
    
    # 应计利息
    accrued_interest: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="应计利息")
    
    # 全价
    full_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="全价")
    
    # 净价
    clean_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="净价")
    
    __table_args__ = (
        UniqueConstraint('bond_code', 'trade_date', name='uk_bond_daily_code_date'),
        Index('idx_bond_daily_code', 'bond_code'),
        Index('idx_bond_daily_date', 'trade_date'),
        Index('idx_bond_daily_code_date', 'bond_code', 'trade_date'),
        # 分区索引
        Index('idx_bond_daily_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<BondDailyData(bond_code={self.bond_code}, trade_date={self.trade_date}, close_price={self.close_price})>"


class BondConvertibleData(BaseFinancialModel, SyncStatusMixin):
    """
    可转债数据模型
    存储可转债的转股相关信息
    """
    __tablename__ = "bond_convertible_data"
    
    # 可转债代码
    bond_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="可转债代码")
    
    # 正股代码
    stock_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="正股代码")
    
    # 正股名称
    stock_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="正股名称")
    
    # 转股价格
    convert_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="转股价格")
    
    # 转股比例
    convert_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="转股比例")
    
    # 转股开始日
    convert_start_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="转股开始日")
    
    # 转股结束日
    convert_end_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="转股结束日")
    
    # 赎回价格
    redeem_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="赎回价格")
    
    # 赎回条件
    redeem_condition: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="赎回条件")
    
    # 回售价格
    put_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="回售价格")
    
    # 回售条件
    put_condition: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="回售条件")
    
    # 转股价值
    convert_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="转股价值")
    
    # 转股溢价率(%)
    convert_premium_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="转股溢价率(%)")
    
    # 纯债价值
    bond_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="纯债价值")
    
    # 纯债溢价率(%)
    bond_premium_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="纯债溢价率(%)")
    
    # 数据日期
    data_date: Mapped[date] = mapped_column(Date, nullable=False, comment="数据日期")
    
    __table_args__ = (
        UniqueConstraint('bond_code', 'data_date', name='uk_bond_convertible_code_date'),
        Index('idx_bond_convertible_bond_code', 'bond_code'),
        Index('idx_bond_convertible_stock_code', 'stock_code'),
        Index('idx_bond_convertible_date', 'data_date'),
        Index('idx_bond_convertible_convert_price', 'convert_price'),
    )
    
    def __repr__(self) -> str:
        return f"<BondConvertibleData(bond_code={self.bond_code}, stock_code={self.stock_code}, data_date={self.data_date})>"


class BondYieldData(BaseFinancialModel, PartitionMixin):
    """
    债券收益率数据模型
    存储各类债券收益率曲线数据
    """
    __tablename__ = "bond_yield_data"
    
    # 数据日期
    data_date: Mapped[date] = mapped_column(Date, nullable=False, comment="数据日期")
    
    # 收益率类型：国债收益率, 企业债收益率, 金融债收益率等
    yield_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="收益率类型")
    
    # 期限（年）
    term: Mapped[Decimal] = mapped_column(Numeric(10, 2), nullable=False, comment="期限(年)")
    
    # 收益率(%)
    yield_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="收益率(%)")
    
    # 信用等级
    credit_level: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="信用等级")
    
    # 市场类型：银行间, 交易所
    market_type: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="市场类型")
    
    # 数据来源
    data_source_detail: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="数据来源详情")
    
    __table_args__ = (
        UniqueConstraint('data_date', 'yield_type', 'term', 'credit_level', 'market_type', 
                        name='uk_bond_yield_date_type_term_credit_market'),
        Index('idx_bond_yield_date', 'data_date'),
        Index('idx_bond_yield_type', 'yield_type'),
        Index('idx_bond_yield_term', 'term'),
        Index('idx_bond_yield_credit', 'credit_level'),
        # 分区索引
        Index('idx_bond_yield_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<BondYieldData(data_date={self.data_date}, yield_type={self.yield_type}, term={self.term}, yield_rate={self.yield_rate})>"


class BondIssueData(BaseFinancialModel):
    """
    债券发行数据模型
    存储债券发行相关的详细信息
    """
    __tablename__ = "bond_issue_data"
    
    # 债券代码
    bond_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="债券代码")
    
    # 发行公告日
    issue_ann_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="发行公告日")
    
    # 发行起始日
    issue_start_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="发行起始日")
    
    # 发行结束日
    issue_end_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="发行结束日")
    
    # 网上发行日
    online_issue_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="网上发行日")
    
    # 网下发行日
    offline_issue_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="网下发行日")
    
    # 计划发行量（万元）
    plan_issue_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="计划发行量(万元)")
    
    # 实际发行量（万元）
    actual_issue_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="实际发行量(万元)")
    
    # 网上发行量（万元）
    online_issue_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="网上发行量(万元)")
    
    # 网下发行量（万元）
    offline_issue_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="网下发行量(万元)")
    
    # 发行价格
    issue_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="发行价格")
    
    # 发行利率(%)
    issue_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="发行利率(%)")
    
    # 认购倍数
    subscription_multiple: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="认购倍数")
    
    # 中签率(%)
    winning_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="中签率(%)")
    
    # 主承销商
    lead_underwriter: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="主承销商")
    
    # 承销方式
    underwrite_method: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="承销方式")
    
    # 发行方式
    issue_method: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="发行方式")
    
    # 发行对象
    issue_target: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="发行对象")
    
    # 募集资金用途
    fund_usage: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="募集资金用途")
    
    __table_args__ = (
        UniqueConstraint('bond_code', name='uk_bond_issue_code'),
        Index('idx_bond_issue_code', 'bond_code'),
        Index('idx_bond_issue_start_date', 'issue_start_date'),
        Index('idx_bond_issue_end_date', 'issue_end_date'),
        Index('idx_bond_issue_underwriter', 'lead_underwriter'),
    )
    
    def __repr__(self) -> str:
        return f"<BondIssueData(bond_code={self.bond_code}, issue_start_date={self.issue_start_date}, actual_issue_amount={self.actual_issue_amount})>"


# 导出所有债券相关模型
__all__ = [
    'BondBasicInfo',
    'BondDailyData',
    'BondConvertibleData', 
    'BondYieldData',
    'BondIssueData',
]